﻿using System;
using System.Linq;
using System.Web.Mvc;
using ControleRepresentante.Common;
using ControleRepresentante.Logic.Models;
using ControleRepresentante.Logic.Repositories;
using ControleRepresentante.Logic.Statistics;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using WebSite.Controllers;
using Attribute = ControleRepresentante.Logic.Models.Attribute;

namespace ControleRepresentante.UnitTests.Controllers
{
    [TestClass]
    public class RepresentanteControllerTests : CRUDControllerTestScenarioBase<RepresentanteController, Representante, IRepresentanteRepository, StatisticsBase>
    {
        private const string Nome = "Nome";
        private const bool Ativo = false;
        private const bool UseJolitex = true;
        private const bool UseTrivium = true;

        protected override RepresentanteController CreateController(bool isAdmin = true)
        {
            if (isAdmin)
            {
                this.LoginAsAdmin();
            }
            return new RepresentanteController(RepositoryProvider, AreaOperacaoRegistry, SessionConfiguration, ControllerExtensionProvider);
        }

        protected override Representante CreateModel()
        {
            return new Representante {Nome = Guid.NewGuid().ToString()};
        }

        protected override ActionResult Create(RepresentanteController controller)
        {
            return controller.Create(Nome, Ativo, UseJolitex, UseTrivium);
        }

        protected override void VerifyModel(Representante model)
        {
            Assert.AreEqual(Nome, model.Nome);
            Assert.AreEqual(Ativo, model.Ativo);
            Assert.AreEqual(UseJolitex, model.UseJolitex);
        }

        protected override ActionResult CreateEmptyFields(RepresentanteController controller)
        {
            return controller.Create(String.Empty, Ativo, UseJolitex, UseTrivium);
        }

        protected override void VerifyModelEmptyFields(Representante model)
        {
            Assert.AreEqual(String.Empty, model.Nome);
            Assert.AreEqual(Ativo, model.Ativo);
            Assert.AreEqual(UseJolitex, model.UseJolitex);
        }

        protected override ActionResult CreateDuplicatedModel(RepresentanteController controller, Representante model)
        {
            return controller.Create(model.Nome, Ativo, UseJolitex, UseTrivium);
        }

        protected override void VerifyDuplicatedModel(Representante originalModel, Representante duplicatedModel)
        {
            Assert.AreEqual(originalModel.Nome, duplicatedModel.Nome);
            Assert.AreEqual(Ativo, duplicatedModel.Ativo);
            Assert.AreEqual(UseJolitex, duplicatedModel.UseJolitex);
        }

        protected override ActionResult Edit(RepresentanteController controller)
        {
            return controller.Edit(Nome, Ativo, UseJolitex, UseTrivium);
        }

        protected override ActionResult EditEmptyFields(RepresentanteController controller)
        {
            return controller.Edit(String.Empty, Ativo, UseJolitex, UseTrivium);
        }

        protected override ActionResult EditDuplicatedModel(RepresentanteController controller, Representante modelToDuplicate)
        {
            return controller.Edit(modelToDuplicate.Nome, Ativo, UseJolitex, UseTrivium);
        }

        #region User

       [TestMethod]
        public void TestDeleteRepresentanteUser()
        {
            RepresentanteController representanteController = CreateController();
            User user = new User{Username = "a"};
            user.SetPasswordFromRawText("aa");
            Representante representante = new Representante { Nome = Nome };
            representante.AddUser(user);
            var representanteRepository = RepositoryProvider.GetRepository<IRepresentanteRepository>();
            representanteRepository.AddModel(representante);
            StatisticsBase statistics;
            Assert.AreEqual(1, representanteRepository.GetModels(out statistics).Count());
            Assert.AreEqual(1, representanteRepository.GetModels(out statistics).First().Users.Count());
            representanteController.Edit(representante.Id);
            representanteController.UserDelete(representante.Users.First().Id);
            ActionResult actionResult = representanteController.Edit(representante.Nome, representante.Ativo, representante.UseJolitex, representante.UseTrivium);
            Assert.AreEqual(1, representanteRepository.GetModels(out statistics).Count());
            Assert.AreEqual(0, representanteRepository.GetModels(out statistics).First().Users.Count());
            Assert.IsInstanceOfType(actionResult, typeof(RedirectToRouteResult));
            RedirectToRouteResult redirectToRouteResult = (RedirectToRouteResult)actionResult;
            Assert.AreEqual("Details", redirectToRouteResult.RouteValues["action"]);
            Assert.AreEqual(representante.Id, redirectToRouteResult.RouteValues["id"]);
        }

        [TestMethod]
        public void TestCreateRepresentanteUser()
        {
            RepresentanteController representanteController = CreateController();
            Representante representante = new Representante { Nome = Nome };
            IRepresentanteRepository representanteRepository = RepositoryProvider.GetRepository<IRepresentanteRepository>();
            representanteRepository.AddModel(representante);
            representanteController.Edit(representante.Id);

            const string Username = "username";
            const string Password = "password";
            const string Email = "email";
            const bool Ativo = true;
            representanteController.UserInsert(Username, Password, Email, Ativo);
            ActionResult actionResult = representanteController.Edit(representante.Nome, representante.Ativo, representante.UseJolitex, representante.UseTrivium);
            representante = representanteRepository.GetModelById(representante.Id);
            Assert.AreEqual(1, representante.Users.Count());
            Assert.AreEqual(Username, representante.Users.First().Username);
            Assert.AreEqual(Ativo, representante.Users.First().Ativo);
            Assert.AreEqual(Email, representante.Users.First().Email);
            Assert.AreEqual(Password.Encrypt(), representante.Users.First().Password);
            Assert.IsInstanceOfType(actionResult, typeof(RedirectToRouteResult));
            RedirectToRouteResult redirectToRouteResult = (RedirectToRouteResult)actionResult;
            Assert.AreEqual("Details", redirectToRouteResult.RouteValues["action"]);
            Assert.AreEqual(representante.Id, redirectToRouteResult.RouteValues["id"]);
        }

        [TestMethod]
        public void TestEditRepresentanteUser()
        {
            RepresentanteController representanteController = CreateController();
            User user = new User{ Username = "a", Email = "c"};
            user.SetPasswordFromRawText("aaaa");
            Representante representante = new Representante { Nome = Nome };
            representante.AddUser(user);
            IRepresentanteRepository representanteRepository = RepositoryProvider.GetRepository<IRepresentanteRepository>();
            representanteRepository.AddModel(representante);
            representanteController.Edit(representante.Id);

            const string EditedUsername = "www";
            const string EditedPassword = "bbbb";
            const string EditedEmail = "cccc";
            const bool EditedAtivo = true;
            representanteController.UserUpdate(user.Id, EditedUsername, EditedPassword, EditedEmail, EditedAtivo);
            ActionResult actionResult = representanteController.Edit(representante.Nome, representante.Ativo, representante.UseJolitex, representante.UseTrivium);
            Assert.IsInstanceOfType(actionResult, typeof(RedirectToRouteResult));
            RedirectToRouteResult redirectToRouteResult = (RedirectToRouteResult)actionResult;
            Assert.AreEqual("Details", redirectToRouteResult.RouteValues["action"]);
            Assert.AreEqual(representante.Id, redirectToRouteResult.RouteValues["id"]);
            user = representanteRepository.GetModelById(representante.Id).Users.First();
            Assert.AreEqual(EditedUsername, user.Username);
            Assert.AreEqual(EditedAtivo, user.Ativo);
            Assert.AreEqual(EditedEmail, user.Email);
            Assert.AreEqual(EditedPassword.Encrypt(), user.Password);
        }

        [TestMethod]
        public void TestCreateRepresentanteUserDuplicatedUsername()
        {
            RepresentanteController representanteController = CreateController();
            User user = new User {Username = "a", Email = "e"};
            user.SetPasswordFromRawText("aaaa");
            Representante representante = new Representante { Nome = Nome };
            representante.AddUser(user);
            RepositoryProvider.GetRepository<IRepresentanteRepository>().AddModel(representante);
            representanteController.Edit(representante.Id);

            const string Password = "password";
            const string Email = "email";
            representanteController.UserInsert(user.Username, Password, Email, true);
            representanteController.Edit(representante.Nome, representante.Ativo, representante.UseJolitex, representante.UseTrivium);
            Assert.AreEqual(1, representante.Users.Count());
        }

        #endregion

        [TestMethod]
        public void TestCreateAndDeleteFullRepresentante()
        {
            this.LoginAsAdmin();
            Guid representanteId = this.CreateRepresentante("my representante", true, "user");
            this.Logout();

            this.LoginAs("user");
            const string VendedorAttributeName = "my vendedor attribute";
            const string FabricaAttributeName = "my fabrica attribute";
            const string TransportadoraAttributeName = "my transportadora attribute";
            const string ClienteAttributeName = "my cliente attribute";
            const string PedidoAttributeName = "my pedido attribute";
            const string RelatorioVisitaAttributeName = "my relatoriovisitaattribute";
            this.CreateAttribute(AttributeType.Vendedor, VendedorAttributeName);
            this.CreateAttribute(AttributeType.Fabrica, FabricaAttributeName);
            this.CreateAttribute(AttributeType.Transportadora, TransportadoraAttributeName);
            this.CreateAttribute(AttributeType.Cliente, ClienteAttributeName);
            this.CreateAttribute(AttributeType.Pedido, PedidoAttributeName);
            this.CreateAttribute(AttributeType.RelatorioVisita, RelatorioVisitaAttributeName);
            Vendedor vendedor = new Vendedor
            {
                CPF = "cpf",
                Identidade = "identidade",
                Nascimento = DateTime.Now,
                Nome = "nome",
            };
            vendedor.AddContato(new Contato
            {
                Tipo = ContatoType.FaxResidencial,
                Valor = "my contato valor",
                Observacao = "my contato observacao",
                Principal = true,
            });
            vendedor.AddConta(new Conta
            {
                Agencia = "agencia",
                Banco = "banco",
                Numero = "numero",
                Observacao = "observacao",
                Principal = true
            });
            vendedor.AddEndereco(new Endereco
            {
                Bairro = "bairro",
                CEP = "cep",
                Cidade = "cidade",
                Complemento = "complemento",
                Estado = "estado",
                Numero = "numero",
                Observacao = "observacao",
                Rua = "rua",
                Tipo = EnderecoType.Residencial,
                Principal = true
            });
            vendedor.AddAttributeValue(new AttributeValue
            {
                Attribute = new Attribute { Name = VendedorAttributeName },
                Value = "my attribute value"
            });
            Guid vendedorId = this.CreateVendedor(vendedor);
            Fabrica fabrica = new Fabrica
            {
                Nome = "nome",
                CNPJ = "cnpj",
                InscricaoEstadual = "inscricao estadual",
            };
            fabrica.AddAttributeValue(new AttributeValue
            {
                Attribute = new Attribute { Name = FabricaAttributeName },
                Value = "my attribute value"
            });
            fabrica.AddContato(new Contato
            {
                Tipo = ContatoType.FaxResidencial,
                Valor = "my contato valor",
                Observacao = "my contato observacao",
                Principal = true
            });
            fabrica.AddConta(new Conta
            {
                Agencia = "agencia",
                Banco = "banco",
                Numero = "numero",
                Observacao = "observacao",
                Principal = true
            });
            fabrica.AddEndereco(new Endereco
            {
                Bairro = "bairro",
                CEP = "cep",
                Cidade = "cidade",
                Complemento = "complemento",
                Estado = "estado",
                Numero = "numero",
                Observacao = "observacao",
                Rua = "rua",
                Tipo = EnderecoType.Residencial,
                Principal = true
            });
            Guid fabricaId = this.CreateFabrica(fabrica);
            Transportadora transportadora = new Transportadora { Nome = "nome" };
            transportadora.AddAttributeValue(new AttributeValue
            {
                Attribute = new Attribute { Name = TransportadoraAttributeName },
                Value = "my transportadora attribute value"
            });
            transportadora.AddContato(new Contato
            {
                Tipo = ContatoType.Nextel,
                Valor = "my transportadora contato valor",
                Observacao = "my transportadora contato observacao",
                Principal = true
            });
            transportadora.AddConta(new Conta
            {
                Agencia = "agencia",
                Banco = "banco",
                Numero = "numero",
                Observacao = "observacao",
                Principal = true
            });
            transportadora.AddEndereco(new Endereco
            {
                Bairro = "bairro",
                CEP = "cep",
                Cidade = "cidade",
                Complemento = "complemento",
                Estado = "estado",
                Numero = "numero",
                Observacao = "observacao",
                Rua = "rua",
                Principal = true
            });
            Guid transportadoraId = this.CreateTransportadora(transportadora);
            Cliente cliente = new Cliente
            {
                RazaoSocial = "razao social",
                NomeFantasia = "nome fantasia",
                Vendedor = new Vendedor {Id = vendedorId},
            };
            cliente.AddAttributeValue(new AttributeValue
            {
                Attribute = new Attribute { Name = ClienteAttributeName },
                Value = "my cliente attribute value"
            });
            cliente.AddContato(new Contato
            {
                Tipo = ContatoType.Nextel,
                Valor = "my transportadora contato valor",
                Observacao = "my transportadora contato observacao",
                Principal = true
            });
            cliente.AddConta(new Conta
            {
                Agencia = "agencia",
                Banco = "banco",
                Numero = "numero",
                Observacao = "observacao",
                Principal = true
            });
            cliente.AddEndereco(new Endereco
            {
                Bairro = "bairro",
                CEP = "cep",
                Cidade = "cidade",
                Complemento = "complemento",
                Estado = "estado",
                Numero = "numero",
                Observacao = "observacao",
                Rua = "rua",
                Principal = true
            });
            Guid clienteId = this.CreateCliente(cliente);

            RelatorioVisita relatorioVisita = new RelatorioVisita
            {
                Data = DateTime.Now,
                Observacao = "sdfsdf sdf sdf sdf sdf dfsg",
                Cliente = new Cliente {Id = clienteId},
                Vendedor = new Vendedor {Id = vendedorId}
            };
            relatorioVisita.AddAttributeValue(new AttributeValue
            {
                Attribute = new Attribute{Name = RelatorioVisitaAttributeName},
                Value = "egdrg rth rtdh rthrt h"
            });
            relatorioVisita.SetRelatorioVisitaJolitex();
            relatorioVisita.RelatorioVisitaJolitex.Ocorrencia = RelatorioVisitaJolitexOcorrencia.ColocouPedido;
            this.CreateRelatorioVisita(relatorioVisita);

            Produto produto = new Produto
            {
                Codigo = "codigo",
                Descricao = "descricao",
                PrecoUnitario = 123.456,
                Quantidade = 345
            };

            Pedido pedido = new Pedido
            {
                CondicaoPagamento = "CondicaoPagamento",
                Observacao = "Observacao",
                PrazoEntrega = "PrazoEntrega",
                Cliente = new Cliente {Id = clienteId},
                Vendedor = new Vendedor {Id = vendedorId},
                Fabrica = new Fabrica {Id = fabricaId},
                Transportadora = new Transportadora {Id = transportadoraId},
            };
            pedido.AddProduto(produto);
            pedido.AddAttributeValue(new AttributeValue
            {
                Attribute = new Attribute { Name = PedidoAttributeName },
                Value = "my attribute value"
            });
            this.CreatePedido(pedido);

            this.CreateUser("username", "password", "email", true);
            
            this.Logout();
            this.LoginAsAdmin();
            this.DeleteRepresentante(representanteId);
        }
    }
}
